

import LoaderItem from "../loader/LoaderItem";
import Debug from "../logSystem/Debug";
import { CCSprite } from "../base/CCComponent";

/*
*ClassName:ResMgr
*Description:TODO
*Date:2019/3/9 14:05
*/

export default class ResMgr {
    //预制体的字典
    private prefabMaps: Object = {};
    //图片帧的字典
    private spriteFrameMaps: Object = {};
    //图集的字典
    private spriteAtlasMaps: Object = {};
    //地图的字典
    private tiledMapAssetMaps: Object = {};
    //龙骨的字典
    private dragonBonesMaps: Object = {};
    //声音的字典
    private audioMaps: Object = {};
    //json的字典
    private jsonMaps: Object = {};
    //json的字典
    private textAssetMaps: Object = {};
    //字体的字典
    private fontMap: Object = {};

    //spine的字典
    private spineMap: Object = {};

    private texture2DMap: Object = {};

    private _loadItemsMap: { [key: string]: LoaderItem } = {};

    private _asyncLoadRes: any[] = [];
    private _isLoading: boolean = false;//是否正在加载资源
    /***
     * url=路径
     * type=类型
     * resolve
     * reject
     * progress
     * 是否加载完直接卸载
     * */
    onLoadRes1(url: string, type: typeof cc.Asset, resolves, rejects, progresss = null, unLoad: boolean = false) {
        let loadTime: any = new Date();
        let resMgr: ResMgr = ResMgr.instance;
        let loaderItem = new LoaderItem(url, type, 3);
        resMgr.addLoadItem(url, loaderItem);

        let loaderObject = {
            url: url,
            loaderItem: loaderItem,
            resolve: resolves,
            reject: rejects,
            progress: progresss,
            isUnLoad: unLoad,
            loadTime: loadTime
        }
        this._asyncLoadRes.push(loaderObject);

        let loadAsset = () => {
            if (this._asyncLoadRes.length <= 0) {
                return;
            }
            if (this._isLoading) {
                return;
            }
            this._isLoading = true;
            let oneLoaderItem = this._asyncLoadRes[0].loaderItem;
            let loaderUrl = this._asyncLoadRes[0].url;
            let isUnLoad = this._asyncLoadRes[0].isUnLoad;
            let resolve = this._asyncLoadRes[0].resolve;
            let reject = this._asyncLoadRes[0].reject;
            let progress = this._asyncLoadRes[0].progress;
            let oneLoadTime = this._asyncLoadRes[0].loadTime;
            oneLoaderItem.load((res: any[]) => {
                let loadFishedTime: any = new Date();
                Debug.log("第一次加载资源url = ", loaderUrl, " => 消耗:" + (loadFishedTime - oneLoadTime) + "毫秒");

                if (!isUnLoad) {
                    if (res[0] instanceof cc.Prefab) {
                        this.prefabMaps[loaderUrl] = res[0];
                    } else if (res[0] instanceof cc.SpriteFrame) {
                        this.spriteFrameMaps[loaderUrl] = res[0]
                    } else if (res[0] instanceof cc.SpriteAtlas) {
                        this.spriteAtlasMaps[loaderUrl] = res[0]
                    }
                    // else if (res[0] instanceof cc.TiledMapAsset) {
                    //     this.tiledMapAssetMaps[url] = res[0]
                    // }
                    else if (res[0] instanceof cc.AudioClip) {
                        this.audioMaps[loaderUrl] = res[0];
                    } else if (res[0] instanceof cc.JsonAsset) {
                        this.jsonMaps[loaderUrl] = res[0].json;
                    } else if (res[0] instanceof cc.TextAsset) {
                        this.textAssetMaps[loaderUrl] = res[0].text;
                    } else if (res[0] instanceof cc.Texture2D) {
                        this.texture2DMap[loaderUrl] = res[0];
                    } else if (res[0] instanceof cc.Font) {
                        this.fontMap[loaderUrl] = res[0];
                    } else {
                        this.spineMap[loaderUrl] = res[0];
                    }
                    // else if (res[0] instanceof sp.SkeletonData) {
                    //
                    //     this.spineMap[loaderUrl] = res[0];
                    // }
                }
                resolve(res[0]);
                if (isUnLoad) {
                    this.onRemoveMemory(loaderUrl);
                }

                this._asyncLoadRes.shift();
                this._isLoading = false;
                loadAsset();

            }, (error: Error) => {
                resMgr.removeLoadItem(loaderUrl);

                this._asyncLoadRes.shift();
                this._isLoading = false;
                loadAsset();

                console.error("资源加载错误" + loaderUrl);

                reject(error);
            }, progress, () => {

            })
        }
        loadAsset();
    }

    onLoadRes(url: string, type: typeof cc.Asset, resolve, reject, progress = null, isUnLoad: boolean = false) {
        let loadTime: any = new Date();
        let resMgr: ResMgr = ResMgr.instance;
        let loaderItem = new LoaderItem(url, type, 3);
        resMgr.addLoadItem(url, loaderItem);
        loaderItem.load((res: any[]) => {
            let loadFishedTime: any = new Date();
            Debug.log("第一次加载资源url = ", url, " => 消耗:" + (loadFishedTime - loadTime) + "毫秒");

            if (!isUnLoad) {
                if (res[0] instanceof cc.Prefab) {
                    this.prefabMaps[url] = res[0];
                } else if (res[0] instanceof cc.SpriteFrame) {
                    this.spriteFrameMaps[url] = res[0]
                } else if (res[0] instanceof cc.SpriteAtlas) {
                    this.spriteAtlasMaps[url] = res[0]
                }
                // else if (res[0] instanceof cc.TiledMapAsset) {
                //     this.tiledMapAssetMaps[url] = res[0]
                // }
                else if (res[0] instanceof cc.AudioClip) {
                    this.audioMaps[url] = res[0];
                } else if (res[0] instanceof cc.JsonAsset) {
                    this.jsonMaps[url] = res[0].json;
                } else if (res[0] instanceof cc.TextAsset) {
                    this.textAssetMaps[url] = res[0].text;
                } else if (res[0] instanceof cc.Texture2D) {
                    this.texture2DMap[url] = res[0];
                } else if (res[0] instanceof cc.Font) {
                    this.fontMap[url] = res[0];
                } else {
                    this.spineMap[url] = res[0];
                }
                // else if (res[0] instanceof sp.SkeletonData) {
                //
                //     this.spineMap[url] = res[0];
                // }
            }

            resolve(res[0]);
            if (isUnLoad) {
                this.onRemoveMemory(url);
            }
        }, (error: Error) => {
            resMgr.removeLoadItem(url);
            console.error("资源加载错误" + url);
            reject(error);
        }, progress, () => {

        })
    }

    //添加元素
    public addLoadItem(name: string, loaderItem: LoaderItem) {
        if (this._loadItemsMap[name]) {
            return;
        }
        this._loadItemsMap[name] = loaderItem;
    }

    //移除元素
    public removeLoadItem(name: string) {
        if (!this._loadItemsMap[name]) {
            return;
        }
        let releaseWithoutRes = {};
        for (let key in this._loadItemsMap) {
            if (key != name) {
                let item = this._loadItemsMap[key];
                if (item) {
                    let resources: any = item.resources;
                    for (let item in resources) {
                        releaseWithoutRes[item] = resources[item]
                    }
                }
            }
        }
        // console.error(releaseWithoutRes)
        this._loadItemsMap[name].releaseWithout(releaseWithoutRes);
        if (this._loadItemsMap[name]) {
            delete this._loadItemsMap[name];
        }
    }

    onRemoveMemory(url: string) {
        this.removeLoadItem(url);
        if (this.prefabMaps[url]) {
            delete this.prefabMaps[url];
        }
        if (this.spriteFrameMaps[url]) {
            delete this.spriteFrameMaps[url];
        }
        if (this.spriteAtlasMaps[url]) {
            delete this.spriteAtlasMaps[url];
        }
        if (this.tiledMapAssetMaps[url]) {
            delete this.tiledMapAssetMaps[url];
        }
        if (this.audioMaps[url]) {
            delete this.audioMaps[url];
        }
        if (this.jsonMaps[url]) {
            delete this.jsonMaps[url];
        }
        if (this.texture2DMap[url]) {
            delete this.texture2DMap[url];
        }
        if (this.fontMap[url]) {
            delete this.fontMap[url];
        }
        if (this.spineMap[url]) {
            delete this.spineMap[url];
        }
    }

    /***
     * 加载spine
     * @param url
     * @param progress
     */
    onLoadSpine(url?: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {
            if (this.spineMap[url]) {
                resolve(this.spineMap[url])
                return;
            }
            this.onLoadRes(url, sp.SkeletonData, resolve, reject, progress);
        })
    }

    /***
     * 加载titleMap
     * @param url
     * @param progress
     */
    onLoadTitleMap(url?: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {
            if (this.tiledMapAssetMaps[url]) {
                resolve(this.tiledMapAssetMaps[url])
                return;
            }
            this.onLoadRes(url, cc.TiledMapAsset, resolve, reject, progress);
        })
    }

    /**
     * laod prefab
     * @param perfabName
     * @param progress    completedCount   totalCount
     * @returns {*}
     */
    onLoadPrefab(url?: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {
            if (this.prefabMaps[url]) {
                resolve(this.prefabMaps[url])
                return;
            }
            this.onLoadRes(url, cc.Prefab, resolve, reject, progress);
        })
    }

    /**
     * load spriteFrame
     * @param name
     * @param cb
     * @returns {*}
     */
    onLoadSpriteFrame(url?: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {
            if (this.spriteFrameMaps[url]) {
                resolve(this.spriteFrameMaps[url])
                return;
            }
            this.onLoadRes(url, cc.SpriteFrame, resolve, reject, progress);
        })
    }

    /**
     * load SpriteAtlas
     * @param name
     * @param cb
     * @returns {*}
     */
    onLoadSpriteAtlas(url?: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {

            if (this.spriteAtlasMaps[url]) {
                resolve(this.spriteAtlasMaps[url])
                return;
            }
            this.onLoadRes(url, cc.SpriteAtlas, resolve, reject, progress);
        })
    }

    onGetSpriteFromAtla(url: string, spriteName: string, sprite: cc.Sprite | CCSprite) {
        if (this.spriteAtlasMaps[url]) {
            let atla: cc.SpriteAtlas = this.spriteAtlasMaps[url];
            sprite.spriteFrame = atla.getSpriteFrame(spriteName);
            return;
        } else {
            this.onLoadSpriteAtlas(url, null).then((res: cc.SpriteAtlas) => {
                sprite.spriteFrame = res.getSpriteFrame(spriteName);
            });
        }
    }

    /**
     * get tmx asset
     * @param tmxName
     * @return {*}
     */
    getTmxAsset(tmxName: string): boolean {
        if (this.tiledMapAssetMaps[tmxName]) return this.tiledMapAssetMaps[tmxName];
        return false
    }

    /**
     * load dragon bones
     * @param dragonBonesDir
     * @param cb
     */
    onLoadDragonBones2(dragonBonesDir: string, cb: Function) {
        let strDir = dragonBonesDir;
        if (this.dragonBonesMaps[strDir] && this.dragonBonesMaps[strDir][0] && this.dragonBonesMaps[strDir][1]) {
            //已经加载
            cb(false, this.dragonBonesMaps[strDir][0], this.dragonBonesMaps[strDir][1]);
            return;
        }
        //load
        cc.loader.loadResDir(strDir, function (err, assets) {
            if (err) {
                return;
            } else {
                var assertArr = new Array(2);
                assets.forEach(function (asset) {
                    if (asset instanceof dragonBones.DragonBonesAsset) {
                        assertArr[0] = asset;
                    }
                    if (asset instanceof dragonBones.DragonBonesAtlasAsset) {
                        assertArr[1] = asset;
                    }
                });
                this.dragonBonesMaps[strDir] = assertArr;

                return cb(false, this.dragonBonesMaps[strDir][0], this.dragonBonesMaps[strDir][1]);
            }
        });
    }

    /**
     * 动态加载龙骨
     * @param animationDisplay 龙骨组件
     * @param path 龙骨地址
     * @param armatureName Armature名称
     * @param newAnimation Animation名称
     * @param completeCallback 动画播放完毕的回调
     * @param playTimes 播放次数 -1是根据龙骨文件 0五险循环 >0是播放次数
     */
    onLoadDragonBones(animationDisplay, path, armatureName, newAnimation, loadCompleteCallback, playCompleteCallback, playTimes = 1) { //动态加载龙骨
        if (!animationDisplay) {
            return;
        }
        if (animationDisplay.armature()) {
            animationDisplay.armature().animation.stop();
        }
        animationDisplay.dragonAsset = null;
        animationDisplay.dragonAtlasAsset = null;
        cc.loader.loadResDir(path, function (err, assets) {
            if (err || assets.length <= 0) return;
            assets.forEach(asset => {
                if (asset instanceof dragonBones.DragonBonesAsset) {
                    animationDisplay.dragonAsset = asset;
                }
                if (asset instanceof dragonBones.DragonBonesAtlasAsset) {
                    animationDisplay.dragonAtlasAsset = asset;
                }
            });

            animationDisplay.armatureName = armatureName;
            animationDisplay.armature().animation.play(newAnimation, playTimes);
            if (playCompleteCallback) {
                animationDisplay.addEventListener(dragonBones.EventObject.COMPLETE, playCompleteCallback);
            }
            loadCompleteCallback && loadCompleteCallback()
        })
    }

    onReleaseDragonBones(url: string) {
        cc.loader.releaseResDir(url, cc.Texture2D);
    }

    /**
     * 音频加载
     * @param name
     * @param cb
     * @return {*}
     */
    onLoadAudio(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void, isUnLoad: boolean = false): Promise<any> {
        return new Promise((resolve, reject) => {
            if (this.audioMaps[url]) {
                resolve(this.audioMaps[url]);
                return;
            }
            this.onLoadRes(url, cc.AudioClip, resolve, reject, progress, isUnLoad);
        })
    }

    /**
     * load json
     * @param name
     * @param cb
     * @return {*}
     */
    onLoadTextAsset(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        let name: string = url;
        let arr = url.split('/');
        if (arr.length > 0) {
            name = arr[arr.length - 1];
        }
        return new Promise((resolve, reject) => {
            if (this.textAssetMaps[name]) {
                console.log('name', name, "/", this.textAssetMaps[name]);
                resolve(this.textAssetMaps[name])
                return;
            }
            this.onLoadRes(url, cc.TextAsset, resolve, reject, progress);
        })
    }

    /**
     * load json
     * @param name
     * @param cb
     * @return {*}
     */
    onLoadJson(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        let name: string = url;
        let arr = url.split('/');
        if (arr.length > 0) {
            name = arr[arr.length - 1];
        }
        return new Promise((resolve, reject) => {
            if (this.jsonMaps[name]) {
                console.log('name', name, "/", this.jsonMaps[name]);
                resolve(this.jsonMaps[name])
                return;
            }
            this.onLoadRes(url, cc.JsonAsset, resolve, reject, progress);
        })
    }

    onLoadDirAllJson(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {
            this.onLoadAllResDir(url, cc.JsonAsset, resolve, reject, progress)
        })
    }

    onLoadDirAllAudioClips(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        return new Promise((resolve, reject) => {
            this.onLoadAllResDir(url, cc.AudioClip, resolve, reject, progress)
        })
    }

    /**
     * load spriteFrame
     * @param name
     * @param cb
     * @returns {*}
     */
    onLoadTexture2D(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        let name: string = url;
        let arr = url.split('/');
        if (arr.length > 0) {
            name = arr[arr.length - 1];
        }
        return new Promise((resolve, reject) => {
            if (this.texture2DMap[name]) {
                resolve(this.texture2DMap[name])
                return;
            }
            this.onLoadRes(url, cc.Texture2D, resolve, reject, progress);
        })
    }

    /**
     * load font
     * @param name
     * @param cb
     * @returns {*}
     */
    onLoadFont(url: string, progress?: (completedCount: number, totalCount: number, item: any) => void): Promise<any> {
        let name: string = url;
        let arr = url.split('/');
        if (arr.length > 0) {
            name = arr[arr.length - 1];
        }
        return new Promise((resolve, reject) => {
            if (this.fontMap[name]) {
                resolve(this.texture2DMap[name])
                return;
            }
            this.onLoadRes(url, cc.Font, resolve, reject, progress);
        })
    }

    //只写了json的  其他待添加修改
    onLoadAllResDir(url: string, type: any, resolve, reject, progress?: (completedCount: number, totalCount: number, item: any) => void): void {
        !progress && (progress = () => {
        });
        let loadTime: any = new Date();
        cc.loader.loadResDir(url, type, progress, (err: Error, res: any) => {
            if (err) {
                console.error("加载资源失败 url = ", url, "/error = ", err);
                reject(err);
                return;
            }
            let loadFishedTime: any = new Date();
            Debug.log("第一次加载文件夹下的所有资源url = ", url, " => 消耗:" + (loadFishedTime - loadTime) + "毫秒");
            res.forEach((item) => {
                if (item instanceof cc.Prefab) {
                    this.prefabMaps[item.name] = res;
                } else if (item instanceof cc.SpriteFrame) {
                    this.spriteFrameMaps[item.name] = res;
                } else if (item instanceof cc.SpriteAtlas) {
                    this.spriteAtlasMaps[item.name] = res;
                } else if (item instanceof cc.JsonAsset) {
                    this.jsonMaps[item.name] = item.json[item.name];
                }
                // else if (item instanceof cc.TiledMapAsset) {
                //     this.tiledMapAssetMaps[item.name] = res;
                // }
                else if (item instanceof cc.AudioClip) {
                    this.audioMaps[item.name] = res;
                } else if (item instanceof cc.Texture2D) {
                    this.texture2DMap[item.name] = res;
                } else if (item instanceof cc.Font) {
                    this.fontMap[item.name] = res;
                } else {
                    this.spineMap[url] = res[0];
                }
            })
            resolve(res);
        })

    }


    _imageUrlDic: any = {};//临时图片集合
    //加载图片
    onLoadImage(sprite: cc.Sprite, url: string = "", type: string = "png") {
        if (!sprite) {
            return;
        }
        if (this._imageUrlDic) {
            for (let key in this._imageUrlDic) {
                if (key === url) {
                    sprite.spriteFrame = this._imageUrlDic[key];
                    return;
                }
            }
        }
        if (!url || url == "") {
            this.onGetSpriteFromAtla('textures/atlas/panel_rank', 'img_head', sprite);
            return;
        }

        cc.loader.load({url: url, type: type}, (error, texture) => {
            if (error) {
                console.log("加在图片错误 + errorInfo =", error, "/再次重新加载图片", sprite.name);
                // this.loadImage(sprite, url, type);
            } else {
                if (sprite && texture) {
                    let spriteFrame = new cc.SpriteFrame(texture);
                    sprite.spriteFrame = spriteFrame;
                    this._imageUrlDic[url] = spriteFrame;
                }
            }
        });
    }

    private isPreLoadResBoolean: boolean = false;//预加载
    private static _instance: ResMgr = null;
    static get instance(): ResMgr {
        if (!this._instance) {
            this._instance = new ResMgr();
        }
        return this._instance;
    }

    constructor() {
    }

    //预加载资源
    async onPreLoadRes() {
        if (this.isPreLoadResBoolean) {
            return;
        }

        this.isPreLoadResBoolean = true;
        // await this.onLoadSpriteAtlas("textures/atlas/itemRes");
        // await this.onLoadSpriteAtlas("textures/atlas/commonRes");
        // await this.onLoadSpriteAtlas("textures/atlas/rolesRes");
        // await this.onLoadSpriteAtlas("textures/atlas/panel_rank");
        // await this.onLoadSpriteFrame('textures/single/sceneGame/bg/background_bottom_left');//预先加载背景图
        //预先加载升级UI
        // await this.onLoadPrefab(PANEL_PATH.PANEL_EMPLOYEE);
        // await this.onLoadPrefab('prefabs/panels/sceneMain/employee/personnelItem');
        // await this.onLoadPrefab('prefabs/panels/sceneMain/employee/adviserItem');
        // await this.onLoadPrefab('prefabs/panels/sceneMain/employee/prestigeItem');
    }
}